/*********************************************************************************
 *      Copyright:  (C) 2025 LingYun IoT System Studio
 *                  All rights reserved.
 *
 *       Filename:  socket.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(30/04/25)
 *         Author:  Guo Wenxue <guowenxue@gmail.com>
 *      ChangeLog:  1, Release initial version on "30/04/25 22:35:04"
 *                 
 ********************************************************************************/
#include <time.h>
#include <stdio.h>
#include <netdb.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include "socket.h"
#include "sqlite.h"
#include "logger.h"

#define CONNECT_RETRY_TIMES 3
#define CONNECT_RETRY_DELAY_MS 200

//初始化socket 
int socket_init(socket_t *sock, const char *hostname, int port)
{
	if ( (NULL == sock) || (NULL == hostname) || (port < 0) )
	{
		log_error("Invalid arguments: sock=%p, hostname=%p, port=%d\n", 
                 sock, hostname, port);
		return -1;
	}
	memset(sock, 0, sizeof(socket_t));

	strncpy(sock->host, hostname, sizeof(sock->host)-1);//服务器主机名ip 
	sock->host[sizeof(sock->host)-1] = '\0';
	sock->port = port;	//服务器端口
	sock->fd = -1;
	sock->saved_flags = 0;
	log_debug("Socket initialized: host=%s, port=%d\n", sock->host, sock->port);
	printf("运行到这1\n");
	return 0;
}

//socket连接
int socket_connect(socket_t *sock)
{
//	int					rv = -1;		
	char                port_str[16]= {0};
//	int					flags;
    int                 retries=0;
	int					status=-1;			
	struct addrinfo 	hints;
	struct addrinfo  	*res=NULL;			
	struct addrinfo 	*ip_buf = NULL;		

	if (NULL == sock || sock->port <= 0)
	{
      		 log_error("Invallid socket paramerers\n");
        	 return -1;
        }
	 // 确保初始状态
   	 if (sock->fd >= 0)
   	 {
        	close(sock->fd);
       	 	sock->fd = -1;
   	 }
     sock->connected = 0;

	 snprintf(port_str, sizeof(port_str), "%d", sock->port);
	 
	 memset(&hints, 0, sizeof(hints));
	 hints.ai_family = AF_INET;
     hints.ai_socktype = SOCK_STREAM;
     printf("运行到这2\n");

	 while (retries < CONNECT_RETRY_TIMES)
	 {
			 log_debug("Connection attempt %d/%d", retries + 1, CONNECT_RETRY_TIMES);
             if ((status = getaddrinfo(sock->host, port_str, &hints, &res)) != 0) 
	     	 {
               	log_error("getaddrinfo [%s:%s] failed: %s\n",
                sock->host, port_str, gai_strerror(status));
            	goto cleanup;
             }
		  printf("3\n");
	     // 遍历所有可能的地址
            for (ip_buf = res; ip_buf != NULL; ip_buf = ip_buf->ai_next)
	        {
				 // 确保前一次尝试的 fd 已关闭
            		if (sock->fd >= 0)
					{
                		close(sock->fd);
                		sock->fd = -1;
            		}
					printf("guangbi\n");
            		// 创建Socket（IPv4）
            		sock->fd = socket(AF_INET, SOCK_STREAM, 0);
            		if (sock->fd < 0) 
					{
                		log_error("socket() failed: %s", strerror(errno));
               			 continue;
            		}
					printf("ipv4\n");
            		// 设置为非阻塞模式并保存原始Flags
           			int flags = fcntl(sock->fd, F_GETFL);
            		if (flags < 0 || fcntl(sock->fd, F_SETFL, flags | O_NONBLOCK) < 0) 
					{
                		log_error("fcntl() failed: %s", strerror(errno));
                		close(sock->fd);
                		sock->fd = -1;
                		continue;
            		}
            		sock->saved_flags = flags;
					       // 转换为 IPv4 地址字符串
            		struct sockaddr_in *addr = (struct sockaddr_in*)ip_buf->ai_addr;
            		char ip_str[INET_ADDRSTRLEN] = {0};
            		inet_ntop(AF_INET, &addr->sin_addr, ip_str, sizeof(ip_str));
            		log_debug("Trying IPv4 address: %s:%d", ip_str, sock->port);
		 // 尝试连接
		 			printf("4\n");
            		status = connect(sock->fd, (struct sockaddr*)addr, sizeof(struct sockaddr_in));
            		if (status == 0)
					{
						log_debug("Immediate IPv4 connection success");
                		goto connection_success;
            		}
					printf("5\n");

            		if (errno != EINPROGRESS) 
	    			{
                		log_warn("Connect failed immediately: %s\n", strerror(errno));
                		close(sock->fd);
                		sock->fd = -1;
                		continue;
            		}
					printf("6\n");

	            	// 等待连接完成
    	        	fd_set writefds;
        	    	FD_ZERO(&writefds);
            		FD_SET(sock->fd, &writefds);
					struct timeval tv = {.tv_sec = 3, .tv_usec = 0};

            		int select_ret = select(sock->fd+1, NULL, &writefds, NULL, &tv);
            		printf("7\n");
					if (select_ret <= 0)
	    			{
                		log_warn("Connect timeout or error: %s\n",
                        select_ret == 0 ? "timeout" : strerror(errno));
                		close(sock->fd);
                		sock->fd = -1;
                		continue;
            		}
					printf("8\n");
            		// 检查连接状态
            		int so_error;
            		socklen_t len = sizeof(so_error);
            		if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, &so_error, &len) < 0 ||
            	   	so_error != 0) 
	    			{
                		log_warn("Connection failed: %s\n",
                        so_error ? strerror(so_error) : "getsockopt failed");
                		close(sock->fd);
                		sock->fd = -1;
                		continue;
            		}
					printf("9\n");
					printf("IPv4 connection success after select\n");
            		printf("32\n");
					goto connection_success;
    		}
        	    printf("11\n");                         
				// 本次尝试失败，准备重试
    	    	freeaddrinfo(res);
    	    	res = NULL;
	
				retries++;
	        	if (retries < CONNECT_RETRY_TIMES)
				{
    	          	log_error("Connection attempt %d/%d failed, retrying in %dms...\n",retries, CONNECT_RETRY_TIMES, CONNECT_RETRY_DELAY_MS);
      				usleep(CONNECT_RETRY_DELAY_MS * 1000);
        		}
printf("10\n");  


  
	 log_error("Failed to connect to %s:%d after %d attempts\n",sock->host, sock->port, CONNECT_RETRY_TIMES);
    		
	 goto cleanup;
	 
	 printf("11\n");

	}
connection_success:
    // 恢复阻塞模式
    if (fcntl(sock->fd, F_SETFL, sock->saved_flags) < 0)
	{
        log_error("Failed to restore socket flags: %s", strerror(errno));
    }
    sock->connected = 1;
	printf("wuyu\n");
    // 仅在 res 未释放时调用 freeaddrinfo
    if (res != NULL)
	{
        freeaddrinfo(res);
        res = NULL;  // 防止后续误用
    }
    return 0;

cleanup:
    if (res != NULL)
	{
        freeaddrinfo(res);
        res = NULL;
    }
    if (sock->fd >= 0)
	{
        close(sock->fd);
        sock->fd = -1;
    }
    sock->connected = 0;
    return 0;
}
#if 0
//判断和设置socket连接标志 
int socket_diag(socket_t *sock)
{
	 if (!sock || sock->fd < 0)
	 {
        	log_error("Invalid socket or fd: sock=%p, fd=%d", sock, sock ? sock->fd : -2);
        	return -1;
   	 }

	int 		error=0;
	socklen_t 	len = sizeof(error);

	if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
       	{
        	log_error("getsockopt failed: %s\n", strerror(errno));
        	sock->connected = 0;
        	return -1;
   	 }

   	 if (error != 0)
	 {
        	log_warn("Socket error: %s\n", strerror(error));
        	sock->connected = 0;
        	return 0;
   	 }

   	 // 额外检查是否真的可写
    	fd_set writefds;
    	struct timeval tv = {.tv_sec = 0, .tv_usec = 1000};
    	FD_ZERO(&writefds);
    	FD_SET(sock->fd, &writefds);
    
    	if (select(sock->fd+1, NULL, &writefds, NULL, &tv) <= 0)
       	{
        	sock->connected = 0;
        	return 0;
    	}

    sock->connected = 1;
    return 1;
}
#endif
//写入数据 
int socket_write(socket_t *sock, const char *data, int bytes)
{

	if (!sock || sock->fd < 0 || !data || bytes <= 0)
       	{
        	log_error("Invalid arguments: sock=%p fd=%d data=%p bytes=%d\n",
                 sock, sock ? sock->fd : -1, data, bytes);
        	return -1;
   	 }

    	int total_sent = 0;
    	fd_set writefds;
    	printf("即将发送的数据: %s\n", data); // 添加调试信息，打印即将发送的数据
		struct timeval tv;

		while (total_sent < bytes)
       	{
        	int remaining = bytes - total_sent;
        	int chunk = remaining > 1024 ? 1024 : remaining;
        	
			tv.tv_sec = 5;
        	tv.tv_usec = 0;

        	FD_ZERO(&writefds);
        	FD_SET(sock->fd, &writefds);

			int select_ret = select(sock->fd + 1, NULL, &writefds, NULL, &tv);
        	if (select_ret <= 0)
        	{
            		log_error("Write timeout or error: %s\n",
                    select_ret == 0 ? "timeout" : strerror(errno));
            		return -1;
        	}

        	int wv = write(sock->fd, data + total_sent, chunk);
        	if (wv <= 0)
	       	{
            		if (errno == EAGAIN || errno == EWOULDBLOCK)
		       	{
                	
				usleep(10000); // 10ms delay
                	
				continue;
            		}
            	log_error("Write failed: %s (fd=%d, sent=%d/%d)\n",
                     strerror(errno), sock->fd, total_sent, bytes);
            	return -1;
        	}
        	total_sent += wv;
    	}
		printf("数据发送成功，共发送了 %d 字节\n", total_sent); // 添加调试信息，打印发送结果
    	return total_sent;
}

/* 读取数据 */
int socket_read(socket_t *sock, char *data, int bytes)
{
	int			rv = 0;

	if ( (NULL == sock) || (NULL == data) )
	{
		
		log_error("NULL pointer");
		return -1;
	}

	rv = read(sock->fd, data, bytes);
	if ( rv <= 0 )
	{	
		log_error("read failure: %s\n", strerror(errno));
		return 0;
	}
	return 1;
}

//关闭socket
int socket_close(socket_t *sock)
{
	if ( NULL == sock )
	{
		
		log_error("NULL pointer\n");
		return 0;
	}
	if (sock->fd >= 0)
	{
		close(sock->fd);
		sock->fd = -1;
	}
	return 1;
}


